#ifndef lock_manager_h
#define lock_manager_h


#include "efsm.hpp"
#include "efsm_event.hpp"


/****  知识点1 ****/
// 背景：inputmanager.hpp已经包含了 lock_manager.hpp ， 
// 此处 lock_manager.hpp内又需要使用inputmanager.hpp内声明的类
// 不可以交叉引用。
// 因此前置声明
// 前置声明注意事项：
// 类或结构体的前置声明, 在其内部只能定义对象指针，因为此时没有办法构造一个具体的对象。
class inputmanager;
class input_dev_param;


class abstract_state_manager_isalso_listener
{
public:
    virtual void Update(inputmanager* in_manager) = 0;

};

// concrete listener
class normal_state_manmager : public abstract_state_manager_isalso_listener
{
    normal_state_manmager();

public:
    static normal_state_manmager* get_normal_state_manmager();
    static normal_state_manmager* p_normal_state_manmager_instance;

    ~normal_state_manmager();

    void Update(inputmanager* in_manager);


private:
    //input_dev_param  dev_para;  //编译报错，见上述知识点1
    //input_dev_param  &dev_para;  编译报错
    input_dev_param  *dev_para;   // 编译OK
};


// concrete listener
class admin_state_manmager : public abstract_state_manager_isalso_listener
{
    admin_state_manmager();

public:
    static admin_state_manmager* get_admin_state_manmager();
    static admin_state_manmager* p_admin_state_manmager_instance;

    ~admin_state_manmager();

    void Update(inputmanager* in_manager);

protected:
private:
    input_dev_param  *dev_para; 
};


// 前置声明注意事项：

// 编译OK
inline void func( input_dev_param  *dev_para) {

}

/* 小结

//1.前置声明的必要性：
// 由上述例子可知，我们可以借助前置声明来避免头文件相互包含，从而顺利编译代码。
// 前置声明是避免头文件相互包含的有效解决方案。

// 2. 前置声明的缺陷展示
// 编译错误

inline void func_2( input_dev_param  *dev_para) {
                   // PS: 下面不一定非要写成 int x = dev_para->input_type; 
    //3;              // 举例解释： 这里直接这样写都是可以编译过的，认为是一条完整的语句。
    dev_para->input_type;  // 所以，这里编译不错，是因为无法访问到input_type成员。                  
}
报错信息：
lock_manager.hpp:64:13: error: invalid use of incomplete type 'class input_dev_param'
lock_manager.hpp:13:7: error: forward declaration of 'class input_dev_param'

 上述报错信息显示： 在前置声明时，不能这样使用。
 即：input_dev_param这个类在本文件内是前置声明的，那么此处不能通过该类的指针来访问其成员。
 解决编译报错的方法：
 此处应该在func_2函数的定义文件内，将前置声明input_dev_param类修改为直接包含其所在的头文件


3. 前置声明和头文件直接包含的区别：
由此可见，某个源文件source.cpp直接包含某个类class A的声明所在头文件source.hpp
 和 只在source.cpp内前置声明class A, 是有区别的。
 当我们希望访问A的成员的时候，我们不应该只是前置声明，而应该做到直接包含相关头文件。(此处就是直接包含souce.hpp)


4. 补充点
PS：头文件和头文件之间相互包含要特别注意，务必要避免相互包含。
    源文件包含头文件不需要注意什么，大胆包含即可。
    因为源文件和头文件几乎不存在相互包含的场景，
    只会在源文件内包含头文件，
    而不会在头文件内包含源文件。
*/





#include "efsm.hpp"
#include "efsm_event.hpp"

EFSM_PTR_DECLEAR(main_set);

EFSM_DECLEAR(normal_mode_efsmsets);






#endif

